package com.minimalist.common.feign.config;

import feign.*;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import feign.form.spring.SpringFormEncoder;
import feign.optionals.OptionalDecoder;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * Feign 配置类
 *
 * @author minimalist
 */
@Configuration
public class FeignConfig{


    /**
     * 创建请求拦截器，用于在请求头中传递 token 等信息
     */
    @Bean
    public RequestInterceptor requestInterceptor(){
        return requestTemplate -> {
            // 传递请求头信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();
            if (attributes != null){
                HttpServletRequest request = attributes.getRequest();
                // 传递 token
                String token = request.getHeader(HttpHeaders.AUTHORIZATION);
                if (token != null){
                    requestTemplate.header(HttpHeaders.AUTHORIZATION, token);
                }

                // 传递租户ID
                String tenantId = request.getHeader("tenant-id");
                if (tenantId != null){
                    requestTemplate.header("tenant-id", tenantId);
                }

                // 传递 traceId
                String traceId = request.getHeader("traceId");
                if (traceId != null){
                    requestTemplate.header("traceId", traceId);
                }
            }

            // 添加Feign标识请求头，用于服务端识别Feign请求
            requestTemplate.header("X-OpenFeign-Request", "true");

            // 移除 Accept-Encoding 请求头，禁用 GZIP 压缩（同时移除大小写版本）
            requestTemplate.removeHeader("accept-encoding");
            requestTemplate.removeHeader("Accept-Encoding");
        };
    }

    /**
     * 表单编码器
     */
    @Bean
    public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> converters){
        return new SpringFormEncoder(new SpringEncoder(converters));
    }

    /**
     * 解码器
     * 使用ResponseEntityDecoder包装SpringDecoder以正确处理ResponseEntity类型和统一响应类型R
     */
    @Bean
    public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> converters){
        return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(converters){
            @Override
            public Object decode(Response response, Type type) throws FeignException, IOException{
                // 增强空响应处理逻辑
                if (response.body() == null || response.body().length() == 0){
                    // 处理空响应体的情况
                    if (type instanceof ParameterizedType parameterizedType){
                        Type rawType = parameterizedType.getRawType();
                        if (rawType == ResponseEntity.class){
                            // 检查是否是ResponseEntity<Void>
                            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                            if (actualTypeArguments.length > 0 &&
                                    (actualTypeArguments[0] == Void.class || actualTypeArguments[0] == void.class)){
                                return ResponseEntity.status(response.status()).build();
                            }
                            return ResponseEntity.status(response.status()).build();
                        } else if (rawType == Optional.class){
                            return Optional.empty();
                        } else if (rawType.getTypeName().endsWith("R")){
                            // 处理统一响应类型R
                            return com.minimalist.common.response.R.ok();
                        }
                    } else if (type == Void.class || type == void.class){
                        return null;
                    }

                    // 对于其他类型，如果响应状态码是成功的，返回null
                    if (response.status() >= 200 && response.status() < 300){
                        return null;
                    }
                }
                return super.decode(response, type);
            }
        }));
    }

    /**
     * 错误解码器，用于捕获异常
     */
    @Bean
    public ErrorDecoder errorDecoder(){
        return (_, response) -> {
            Exception exception = new Exception("服务调用失败: " + response.status() + " " + response.reason());

            // 将异常保存到请求上下文中，以便在降级处理中获取
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            if (requestAttributes != null){
                requestAttributes.setAttribute("exception", exception, RequestAttributes.SCOPE_REQUEST);
            }

            return exception;
        };
    }

    // 移除 Retryer 配置，使用 Sentinel 的重试机制

    /**
     * 配置自定义Feign日志记录器
     */
    @Bean
    public Logger feignLogger(){
        return new CustomFeignLogger();
    }

    /**
     * 配置Feign日志级别
     */
    @Bean
    public Logger.Level feignLoggerLevel(){
        // FULL级别会记录请求和响应的头信息、正文和元数据
        return Logger.Level.FULL;
    }

    /**
     * 配置请求超时
     */
    @Bean
    public Request.Options options(){
        return new Request.Options(
                10, TimeUnit.SECONDS, // 连接超时
                60, TimeUnit.SECONDS, // 读取超时
                true); // 是否跟随重定向
    }
}